/*
 *    Copyright (c) 2018-2025, cloud All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: cloud
 */
package com.fuyao.cloud.asset.acceptancecheck.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyao.cloud.admin.api.feign.RemoteDeptService;
import com.fuyao.cloud.asset.acceptancecheck.mapper.AssetAcMapper;
import com.fuyao.cloud.asset.acceptancecheck.service.AssetAcService;
import com.fuyao.cloud.asset.acceptancechecklist.service.AssetAcListService;
import com.fuyao.cloud.asset.card.service.AssetAssetcardService;
import com.fuyao.cloud.asset.constant.AssetAcConstant;
import com.fuyao.cloud.asset.constant.AssetConstant;
import com.fuyao.cloud.asset.constant.PurchaseConstant;
import com.fuyao.cloud.asset.constant.WarehousConstant;
import com.fuyao.cloud.asset.contract.service.AssetContractService;
import com.fuyao.cloud.asset.dto.ac.AcSearchDTO;
import com.fuyao.cloud.asset.dto.ac.AssetAcCreateDTO;
import com.fuyao.cloud.asset.dto.ac.AssetAcEditDTO;
import com.fuyao.cloud.asset.entity.AssetCard;
import com.fuyao.cloud.asset.entity.AssetContract;
import com.fuyao.cloud.asset.entity.AssetSupplier;
import com.fuyao.cloud.asset.entity.ac.AssetAc;
import com.fuyao.cloud.asset.entity.ac.AssetAcList;
import com.fuyao.cloud.asset.entity.warehous.Warehous;
import com.fuyao.cloud.asset.enums.AssetStatusEnum;
import com.fuyao.cloud.asset.purchaseorder.service.AssetPurchaseorderService;
import com.fuyao.cloud.asset.supplier.service.AssetSupplierService;
import com.fuyao.cloud.asset.vo.ac.AcListVO;
import com.fuyao.cloud.asset.vo.ac.AcPageVO;
import com.fuyao.cloud.asset.vo.ac.AssetAcExcelVO;
import com.fuyao.cloud.asset.warehous.service.WarehousService;
import com.fuyao.cloud.common.core.constant.CommonConstants;
import com.fuyao.cloud.common.core.model.BaseEntity;
import com.fuyao.cloud.common.core.util.DictItemOption;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.data.datascope.DataScope;
import com.fuyao.cloud.common.data.resolver.DictItemResolver;
import com.fuyao.cloud.common.data.resolver.NumberResolver;
import com.fuyao.cloud.common.data.resolver.ParamResolver;
import com.fuyao.cloud.common.security.service.CloudUser;
import com.fuyao.cloud.common.security.util.SecurityUtils;
import com.fuyao.cloud.space.entity.RoomHouse;
import com.fuyao.cloud.space.entity.RoomPosition;
import com.fuyao.cloud.space.house.service.RoomHouseService;
import com.fuyao.cloud.space.position.service.RoomPositionService;
import com.fuyao.cloud.space.vo.PositionVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 验收管理
 *
 * @author liyue
 * @date 2021-12-03 09:41:17
 */
@Service
@AllArgsConstructor
public class AssetAcServiceImpl extends ServiceImpl<AssetAcMapper, AssetAc> implements AssetAcService {

    private final AssetContractService contractService;
    private final AssetSupplierService supplierService;
    private final AssetAcListService assetAcListService;
    private final RoomHouseService houseService;
    private final RoomPositionService positionService;
    private final AssetPurchaseorderService purchaseorderService;
    private final WarehousService warehousService;
    private final AssetAssetcardService assetcardService;

    @Override
    public boolean save(AssetAc entity) {
        setFieldValue(entity);
        boolean hasSave = super.save(entity);
        if (hasSave) {
            this.assetAcListService.saveOrUpdateAcList(entity);
        }
        return hasSave;
    }

    @Override
    public boolean updateById(AssetAc entity) {
        setFieldValue(entity);
        boolean hasUpdate = super.updateById(entity);
        if (hasUpdate) {
            this.assetAcListService.saveOrUpdateAcList(entity);
        }
        // 审批完成验收单时，修改采购订单已收货数量
        if(AssetStatusEnum.APPROVE.getCode().equals(entity.getStatus())){
            finishAssetAc(entity);
        }
        return hasUpdate;
    }

    @Override
    public List listAssetAc(QueryWrapper<AssetAc> query) {
        List<AssetAc> assetAcList = this.getBaseMapper().selectListByScope(query, new DataScope());
        Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(AssetAcConstant.DICT_OPTION_TYPES);
        return assetAcList.stream().map(ac -> {
            AssetAcExcelVO excelVO = new AssetAcExcelVO();
            BeanUtil.copyProperties(ac, excelVO);
            excelVO.setStatus(DictItemResolver.getDictOptionLabel(resultMap.get(AssetAcConstant.ASSET_AC_STATUS), String.valueOf(ac.getStatus())));
            excelVO.setMethod(DictItemResolver.getDictOptionLabel(resultMap.get(AssetConstant.PURCHASE_WAY), ac.getMethod()));
            excelVO.setCurrencyType(DictItemResolver.getDictOptionLabel(resultMap.get(AssetConstant.CURRENCY_TYPE), ac.getCurrencyType()));
            return excelVO;
        }).collect(Collectors.toList());
    }

    @Override
    public AssetAcCreateDTO create() {
        AssetAcCreateDTO createDTO = new AssetAcCreateDTO();
        // 可选项和树
        CloudUser user = SecurityUtils.getUser();
        createDTO.setCreateId(user.getId());
        createDTO.setCreateBy(user.getName());
        createDTO.setCreateTime(LocalDateTimeUtil.now());
        createDTO.setUnid(UUID.randomUUID().toString());
        createDTO.setStatus(AssetAcConstant.AC_DEFAULT_STATUS);
        createDTO.setCurrencyType(PurchaseConstant.PURCHASE_DEFAULT_CURRENCY_TYPE);
        createDTO.setType(PurchaseConstant.PURCHASE_DEFAULT_TYPE);
        createDTO.setDetailed(StrUtil.EMPTY);
        createDTO.setDeptId(user.getDeptId());
        createDTO.setDeptFullname(user.getFullName());
        createDTO.setDictOption(getDictOption());

        String caseKey = ParamResolver.getStr("ASSETAC_CASE_VALUE", "AC");
        Map<String, String> numberMap = NumberResolver.getNumberMap(AssetAcConstant.AC_NUMBER_TYPE, DateUtil.format(new Date(), DatePattern.SIMPLE_MONTH_PATTERN), 5L).getData();
        createDTO.setCaseid(caseKey + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN) + numberMap.get("code"));
        return createDTO;
    }

    @Override
    public AssetAcEditDTO edit(Long id) {
        AssetAc assetAc = this.getById(id);
        Assert.isTrue(ObjectUtils.isNotEmpty(assetAc), String.format("%s不合法", id));

        AssetAcEditDTO editDTO = new AssetAcEditDTO();
        BeanUtil.copyProperties(assetAc, editDTO);
        List<AssetAcList> assetAcList = assetAcListService.getBaseMapper().selectList(Wrappers.<AssetAcList>query().lambda().eq(AssetAcList::getAcId, assetAc.getId()));
        editDTO.setAcList(assetAcList);
        editDTO.setDictOption(getDictOption());
        return editDTO;
    }

    private AssetAcCreateDTO.DictOption getDictOption() {
        Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(AssetAcConstant.DICT_OPTION_TYPES);
        AssetAcCreateDTO.DictOption dictOption = new AssetAcCreateDTO.DictOption();
        dictOption.setStatusList(resultMap.get(AssetAcConstant.ASSET_AC_STATUS));
        dictOption.setPurchaseWayList(resultMap.get(AssetConstant.PURCHASE_WAY));
        dictOption.setCurrencyTypeList(resultMap.get(AssetConstant.CURRENCY_TYPE));
        dictOption.setContractTreeList(contractService.selectContractTree(Wrappers.query(new AssetContract())));
        AssetSupplier fyAssetSupplier = new AssetSupplier();
        fyAssetSupplier.setType("V");
        dictOption.setSupplierTreeList(supplierService.selectTree(Wrappers.query(fyAssetSupplier)));
        List<Tree<String>> treeList = houseService.selectTree();
        dictOption.setHouseTreeList(treeList);
        dictOption.setPositionTreeList(positionService.selectTree(Wrappers.query(new RoomPosition())));
        return dictOption;
    }

    @Override
    public IPage<AcPageVO> getAcPage(Page page, QueryWrapper<AssetAc> query) {
        Page<AssetAc> curPage = this.baseMapper.selectPageByScope(page, query, new DataScope());
        Page<AcPageVO> resultPage = new Page(curPage.getCurrent(), curPage.getSize(), curPage.getTotal());
        List<AssetAc> records = curPage.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            resultPage.setRecords(records.stream().map(ac -> {
                AcPageVO pageVO = new AcPageVO();
                BeanUtil.copyProperties(ac, pageVO);
                List<AcListVO> acList = this.assetAcListService.getAcList(ac);
                pageVO.setAcList(acList);
                return pageVO;
            }).collect(Collectors.toList()));
        }
        return resultPage;
    }

    @Override
    public IPage<AssetAc> page(Page page, QueryWrapper queryWrapper, AcSearchDTO searchDTO) {
        queryWrapper.eq("del_flag", 0);
        return this.baseMapper.page(page, queryWrapper, searchDTO, new DataScope());
    }

    @Override
    public R batchDelete(List<Long> ids) {
        List<AssetAc> acList = this.list(Wrappers.<AssetAc>query().lambda().in(BaseEntity::getId, ids));
        if (CollUtil.isEmpty(acList)) {
            return R.failed("未找到相应的验收数据");
        }
        CloudUser user = SecurityUtils.getUser();
        boolean allMatch = acList.stream().allMatch(assetAc -> AssetStatusEnum.DRAFT.getCode().equals(assetAc.getStatus()) && user.getId().equals(assetAc.getCreateId()));
        if (!allMatch) {
            return R.failed("只能删除草稿状态且创建用户为当前用户的验收数据");
        }
        boolean remove = this.assetAcListService.remove(Wrappers.<AssetAcList>query().lambda().in(AssetAcList::getParentId, ids));
        boolean delete = this.removeBatchByIds(ids);
        if (!delete && !remove) {
            return R.failed("删除失败，请检查数据有效性");
        }
        return R.ok(CommonConstants.SUCCESS, "删除成功");
    }

    @Transactional
    @Override
    public R createNinorder(AssetAc assetAc) {
        long count = warehousService.count(Wrappers.<Warehous>query().lambda().eq(Warehous::getParentCaseid, assetAc.getCaseid()).eq(Warehous::getType, WarehousConstant.WAREHOUS_CLASSIFY_0));
        if (count > 0) {
            return R.failed("设备验收单已生成入库上架单");
        }
        List<AssetAcList> acList = this.assetAcListService.list(Wrappers.<AssetAcList>query().lambda().eq(AssetAcList::getParentId, assetAc.getId()));
        assetAc.setAcList(acList);
        Assert.isTrue(CollUtil.isNotEmpty(assetAc.getAcList()), "无上架资产信息");
        // 生成设备信息
        List<AssetCard> assetCardList = this.assetcardService.generateByAssetCardList(assetAc);
        // 生成入库单
        boolean warehouseB = this.warehousService.generateByWarehouse(assetAc, assetCardList);

        // 修改验收单为已完成
        assetAc.setStatus(AssetStatusEnum.FINISH.getCode());
        this.updateById(assetAc);
        return R.ok((warehouseB), "上架成功");
    }

    /**
     * 完成验收时更新 已收货数量
     *
     * @param entity 采购主单对象
     */
    private void finishAssetAc(AssetAc entity) {
        LambdaQueryWrapper<AssetAcList> lambdaQueryWrapper = Wrappers.<AssetAcList>query().lambda().eq(AssetAcList::getBatchnumber, entity.getBatchnumber());
        List<AssetAcList> acList = this.assetAcListService.list(lambdaQueryWrapper);
        purchaseorderService.updateArrivedQuantity(acList, entity.getBatchnumber());
    }

    private void setFieldValue(AssetAc entity) {
        // 补充金额和清单信息
        List<AssetAcList> assetAcList = entity.getAcList();
        if (CollUtil.isNotEmpty(assetAcList)) {
            StringBuilder detailed = new StringBuilder();
            assetAcList.forEach(p -> detailed.append(p.getName()).append(","));
            detailed.deleteCharAt(detailed.length() - 1);
            // 计算总金额
            long amount = assetAcList.stream().collect(Collectors.summarizingLong((AssetAcList::getAmountLong))).getSum();
            entity.setAmount(new BigDecimal(amount));
            entity.setDetailed(detailed.toString());
        }
        String caseKey = ParamResolver.getStr("ASSETAC_CASE_VALUE", "AC");
        if (StrUtil.isEmpty(entity.getBatchnumber())) {
            CloudUser user = SecurityUtils.getUser();
            String batchNumber = NumberResolver.getCodeByDateTime(caseKey, user.getId(), 5);
            entity.setBatchnumber(batchNumber);
        }
        if (ObjectUtils.isNotEmpty(entity.getContractId()) && entity.getContractId() > 0) {
            AssetContract contract = this.contractService.getById(entity.getContractId());
            entity.setContractName(contract.getName());
            entity.setContractNumber(contract.getContractId());
        }
        if (ObjectUtils.isNotEmpty(entity.getSupplierId()) && entity.getSupplierId() > 0) {
            AssetSupplier supplier = this.supplierService.getById(entity.getSupplierId());
            entity.setSupplierName(supplier.getName());
        }
        if (ObjectUtils.isNotEmpty(entity.getHouseId()) && entity.getHouseId() > 0) {
            RoomHouse roomHouse = this.houseService.getById(entity.getHouseId());
            entity.setHouseName(roomHouse.getName());
            entity.setFullLocation(roomHouse.getParentFullname() + "." + roomHouse.getName());
        }
        if (ObjectUtils.isNotEmpty(entity.getLocationId()) && entity.getLocationId() > 0) {
            PositionVO positionVO = this.positionService.getPositionById(entity.getLocationId());
            entity.setFullLocation(positionVO.getFullLocation());
        }
    }
}
